/*
 * Copyright (C) 2012  - 2013 The playserver  Project
 * Author:longwuwei
 * All Rights Reserved.
 */

#include "Mediaservice.h"
Mediaservice::Mediaservice()
{
    HearBeatTick = 60;
    runFlag = 0;
    initFlag = 0;
}

Mediaservice::~Mediaservice()
{
    runFlag = 0;
}

int Mediaservice::Svr_Start(void)
{
    /*
     *
     * init svr config
     */
    if(this->svrConfig.init() != SUCCESS)
    {
        printf("svrConfig init error! \r\n");
        return FAILURE;
    }

    /**
     * init svr log
     */
    this->svrLog.init(this->svrConfig.log_path);
    this->svrLog.set_loglvl(this->svrConfig.loglevel);

    /**
     *init  svr info
     */
    this->svrInfo.init(&this->svrConfig,this->get_core_version());

    /**
	* init svr file mamange utils class
	*/
	if(this->svrFileManage.init(&this->svrConfig,&this->svrLog) != SUCCESS)
	{
		this->svrLog.log_fmt(LOG_ERR,"svrFileManage init error! \r\n");
		return FAILURE;
	}

	/*
	 * cdn manage init
	 */
	if(this->svrCdnManage.init() != SUCCESS)
	{
		this->svrLog.log_fmt(LOG_ERR,"svrCdnManage init error! \r\n");
		return FAILURE;
	}

    /*
     * init svr task
     */
    if(this->svrTask.init(&this->svrConfig,&this->svrLog,&this->svrFileManage)!= SUCCESS)
    {
        this->svrLog.log_fmt(LOG_ERR,"svrTask init error!");
        return FAILURE;
    }

    /*
     * init svr client utils
     */
    if(this->svrClient.init(&this->svrConfig,&this->svrTask,&this->svrLog,&this->svrFileManage,DFLT_MIN_CONN_SIZ)!= SUCCESS)
    {
        this->svrLog.log_fmt(LOG_ERR,"svrClient init error!");
        return FAILURE;
    }


    /*
     * init svr net service
     */
    if(this->init(this->svrConfig.listen_ip , this->svrConfig.listen_port , this->svrConfig.svr_max_connect_count,this->svrConfig.svr_handle_threads) != SUCCESS)
    {
    	this->svrLog.log_fmt(LOG_ERR,"service init error!");
        return FAILURE;
    }

    /*
     * svr run flag
     */
    runFlag = 1;

    /*
     * start sverver
     */
    return this->start();
}

int Mediaservice::Svr_Status(void)
{
    return this->runFlag;
}

int Mediaservice::Svr_Stop(void)
{
    if(runFlag == 1)
    {
        printf("NetServer stop...\r\n");
        runFlag = 0;
        return this->stop();
    }
    else
    {
        return 0;
    }
}

/*
* net handle interface
*Svr_TransFile:trans file
*/
NEXT_OPRATION  Mediaservice::Svr_TransFile(user_token * token,buf_chunk * sock_buf)
{
    if(token->filefd >= 0)
    {
        /*
        * set total file trans size
        */
        if(token->trans_size == 0)
        {
            token->trans_size = token->hFile_size;
        }

        /*
        *set trans time out:3600 seconds
        */
        sock_buf->size = 0;
        sock_buf->offset = 0;
        token->have_trans_size = 0;
        token->recv_send_flag = FALSE;

        lseek(token->filefd,token->hFile_offset, SEEK_SET);
        fcntl(token->filefd, F_SETFD, FD_CLOEXEC);
        return DO_TRANSFILE;
    }

    return DO_CLOSE;
}

/*
*inherit virtual function
*/
NEXT_OPRATION Mediaservice::accept_completed(user_token *& token,buf_chunk * sock_buf)
{
    user_token * ptoken = NULL;
    svrClient.alloc(&ptoken);
    ptoken->type = INVALID_TYPE;
    token = ptoken;
    return DO_RECV;
}
/*
*connect_completed
*/
NEXT_OPRATION Mediaservice::connect_completed(user_token * token,buf_chunk * sock_buf)
{
    NEXT_OPRATION nOpt = DO_CLOSE;
    if(token != NULL)
    {
        switch(token->type)
        {
            case SVR_HEARTBEAT:
                {
                    sock_buf->offset = 0;
                    sock_buf->size = svrTask.struct_heartbeat_data(sock_buf->buffer,sock_buf->buf_len);
                    nOpt = DO_SEND;
                    this->svrLog.log_fmt(LOG_INFO,"SVR_HEARTBEAT connect ok,begin send:%s\r\n",sock_buf->buffer);
                }
                break;
            default:
              nOpt = DO_CLOSE;
              break;
        }
    }
    return nOpt;
}
/*
*receive_completed
*/
NEXT_OPRATION  Mediaservice::receive_completed(user_token * token,buf_chunk * sock_buf)
{
    if(token == NULL)
    {
        /*do none, must close*/
        return DO_CLOSE;
    }

    /*token type*/
    switch(token->type)
    {
        case SVR_HEARTBEAT:
            {
            	if(this->svrTask.write_heartbeat_data(sock_buf->buffer,sock_buf->offset,token->recv_send_flag) != sock_buf->offset)
            	{
            		return DO_CLOSE;
            	}

            	if(token->recv_send_flag == FALSE)
            	{
            		token->recv_send_flag = TRUE;
            	}

            	return DO_RECV;
            }
            break;
        case INVALID_TYPE:
            {
                token->index = 0;
                token->trans_size = 0;
                token->have_trans_size = 0;
                token->tConnTime = time(NULL);
                Client_Type ctype = svrClient.anylsis_client_type(sock_buf->buffer,sock_buf->offset,token);
                /*check is receive completed*/
                if(ctype == ON_RECV_TYPE)
                {
                    /*must < 32 KB*/
                    if(sock_buf->offset >= 32768)
                    {
                        return DO_CLOSE;
                    }
                    /*go on receive*/
                    return DO_RECV;
                }
                else
                {
                    this->svrLog.log_fmt(LOG_ALL,"[%s]Request Data:%s",token->key,sock_buf->buffer);
                    sock_buf->size =  sock_buf->offset;
                    sock_buf->offset = 0;
                    printf("%d %s",ctype,sock_buf->buffer);
                }

                /*check request type*/
                if(ctype == HTTP_ADMIN_CLIENT)
                {
                    /*send response*/
                    sock_buf->size = (ulong)http::struct_response_header(sock_buf->buffer,HTML,this->svrInfo.readSvrInfo());
                }
                else if(ctype == HTTP_BROWSE)
                {
                    /*send response*/
                    sock_buf->size = (ulong)http::struct_crossxml_doma_response_header(sock_buf->buffer);
                }
                else if(ctype ==  CDN_AUTH_CLIENT)
                {
                	return DO_WAIT;
                }
                else
                {
                    /*set type INVALID ,return 400 code*/
                    token->type = INVALID_TYPE;
                    sock_buf->size = (ulong)http::struct_response_header(sock_buf->buffer,(HTTP_MIME)token->fmt,401);
                }
            }
            break;
        default:
        	return DO_CLOSE;
        	break;
    }

    /*default do send*/
    return DO_SEND;
}
/*
*send_completed
*/
NEXT_OPRATION Mediaservice::send_completed(user_token * token,buf_chunk * sock_buf)
{
    if(token == NULL)
    {
          /*do none, must close*/
          return DO_CLOSE;
    }

    switch(token->type)
    {
          case HTTP_BROWSE:
          case HTTP_ADMIN_CLIENT:
                  return DO_CLOSE;
                  break;
          case SVR_HEARTBEAT:
				  {
					  token->recv_send_flag = FALSE;
					  memset(sock_buf->buffer,'\0',sock_buf->buf_len);
					  sock_buf->offset = 0;
					  sock_buf->size = 0;
					  /*read heartbeat data*/
					  sock_buf->size = this->svrTask.read_heartbeat_data(sock_buf->buffer,sock_buf->buf_len);
					  if(sock_buf->size > 0)
					  {
						  return DO_SEND;
					  }
					  else
					  {
						  return DO_RECV;
					  }
				  }
          case CDN_AUTH_CLIENT:
        	  	return DO_CLOSE;
        	  	break;
          default:
                return DO_CLOSE;
                break;
    }
    /*default do recv*/
    return DO_RECV;
}

/**
 *trans_heartbeat,check session is alive
 */
NEXT_OPRATION  Mediaservice::trans_heartbeat(user_token * token)
{
	if(token == NULL)
	{
		  /*do none, must close*/
		  return DO_CLOSE;
	}

	/*
	 * go on trans file
	 * */
	return DO_TRANSFILE;
}

/*
*trans_completed
*/
NEXT_OPRATION  Mediaservice::trans_completed(user_token * token,buf_chunk * sock_buf)
{
     this->svrLog.log_fmt(LOG_INFO,"trans completed!\r\n");
     return DO_CLOSE;
}
/*
*send_wait_compledted
*/
NEXT_OPRATION Mediaservice::recv_or_send_wait_completed(user_token * token,buf_chunk * sock_buf)
{
    if(token == NULL)
    {
        return DO_CLOSE;
    }

    switch(token->type)
    {
    	case CDN_AUTH_CLIENT:
			{
				/*check wait is time out*/
				if(time(NULL) - token->tConnTime > 5)
				{
					 this->svrLog.log_fmt(LOG_INFO,"[%s]CDN_AUTH_CLIENT check wait is time out",token->key);
					 return DO_CLOSE;
				}
				/*check auth result*/
				AUTH_STATUS authstatus = AUTH_FAILURE;
				if(authstatus == AUTH_WAIT || authstatus == AUTH_DISCONN_WAIT)
				{
					return DO_WAIT;
				}
				else if(authstatus == AUTH_FAILURE)
				{
					/*send auth failure result*/
					token->recv_send_flag = TRUE;
					sock_buf->offset = 0;
					memset(sock_buf->buffer,'\0',sock_buf->buf_len);
					strcpy(sock_buf->buffer,"401 Unauthorized\r\n\r\n");
					sock_buf->size = strlen(sock_buf->buffer);
					this->svrLog.log_fmt(LOG_ALL,"[%s]Response Data:%s",token->key,sock_buf->buffer);
				}
				else
				{
					/*send auth success result*/
					token->recv_send_flag = TRUE;
					sock_buf->offset = 0;
					memset(sock_buf->buffer,'\0',sock_buf->buf_len);
					strcpy(sock_buf->buffer,"200 OK\r\n\r\n");
					sock_buf->size = strlen(sock_buf->buffer);
					this->svrLog.log_fmt(LOG_ALL,"[%s]Response Data:%s",token->key,sock_buf->buffer);
				}

				/*set resulte*/
				return DO_SEND;
			}
    		break;
        default:
            return DO_CLOSE;
            break;
    }

    return DO_WAIT;
}
/*
*send_wait_compledted
*/
void Mediaservice::close_completed(user_token * token,buf_chunk * sock_buf,NET_ERROR_CODE error)
{
    /*connect close log*/
    if(error != INVALID_ERROR && error != CLIENT_CLOSED)
    {
        this->svrLog.log_fmt(LOG_INFO,"client close completed,code:%d",error);
    }
    /*handle close opration*/
    if(token != NULL)
    {
        switch(token->type)
        {
            case SVR_HEARTBEAT:
                {
                	svrTask.handle_heartbeat_data();
                    svrTask.svr_heartbeat_task = TASK_CLOSE;
                }
                break;
            case CDN_AUTH_CLIENT:
				{
					/*do nothing*/
				}
				break;
            default:break;
        }

        /*
        *must free token
        */
        svrClient.free(token);
    }
}

/*
*svr log
*/
int  Mediaservice::log_fmt(int nloglvl,const char * lpszFormat , ...)
{
    va_list argList;
    va_start(argList, lpszFormat);

    char m_szMsg[8192];
    memset(m_szMsg,'\0',8192);
    vsprintf(m_szMsg, lpszFormat, argList);
    printf(m_szMsg);
    this->svrLog.log_fmt_arglist(nloglvl,lpszFormat,argList);

    va_end(argList);

    return SUCCESS;
}
/*
*Svr HearBeat
*/
void  Mediaservice::Svr_HearBeat(void)
{
    /*HearBeat*/
    if(svrTask.svr_heartbeat_task == TASK_CLOSE)
    {
        /*update config*/
        this->svrConfig.update();
        this->svrConfig.set_authsvr_address();

        /*get stream post connect*/
         svrTask.svr_heartbeat_task = TASK_RUN;

         user_token * token = NULL;
         svrClient.alloc(&token);
         token->type = SVR_HEARTBEAT;
         token->local_addr.sin_family = AF_INET;
         token->local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
         token->local_addr.sin_port = htons(0);
         token->remote_addr.sin_family = AF_INET;
         token->remote_addr.sin_addr.s_addr = inet_addr(this->svrConfig.auth_ip);
         token->remote_addr.sin_port = htons(this->svrConfig.auth_port);
         post_usr_connect(token,NET_TCP);
    }
}

/*
*Svr_Run_task
*/
void  Mediaservice::Svr_Run_task(void)
{

}

/*
*Svr_Run
*/
int Mediaservice::Svr_Run(long useconds)
{
    if(initFlag == 0)
    {
        initFlag = 1;
    }

    /*
     * svr heartbeat
     * 1 seconds
     */
    if(this->HearBeatTick * useconds >= 1000000)
    {
        this->Svr_HearBeat();
        this->Svr_Run_task();

        this->HearBeatTick = 0;
    }

    /*
     *svrTask handle run
     */
    this->svrTask.run(useconds);

    /*
     * svrClient handle run
     * */
    this->svrClient.run();



    /**
	 * svr file manage run
	 */
	this->svrFileManage.run(useconds);

    /**
	 *refresh  server info
	 */
	this->svrInfo.refresh(useconds,this->get_connect_pool_use_count(),
			this->get_connect_pool_unuse_count(),
			this->get_connect_pool_count(),
			this->get_buf_pool_unuse_count(),
			this->get_buf_pool_count(),
			this->svrClient.get_free_count(),
			this->svrClient.get_count(),
			this->svrTask.get_task_count(),
			this->svrTask.get_free_task_count());

    /*
     *time tick
     */
    this->HearBeatTick ++;

    return 0;
}
